{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 介绍 旧的 API mode：chat completions 的 同步、异步 和 流式、非流式 用法\n",
    "共四种用法：\n",
    "1. 同步非流式输出\n",
    "2. 同步流式输出\n",
    "    ```python\n",
    "    from openai import OpenAI\n",
    "    ```\n",
    "3. 异步非流式输出\n",
    "4. 异步流式输出\n",
    "    ```python\n",
    "    from openai import AsyncOpenAI\n",
    "    ```\n",
    "\n",
    "### 介绍 新的 API mode：responses\n",
    "\n",
    "### 介绍 function call 的用法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import asyncio\n",
    "from openai import OpenAI, AsyncOpenAI\n",
    "from dotenv import load_dotenv\n",
    "from typing import AsyncGenerator\n",
    "\n",
    "# 初始化环境变量\n",
    "load_dotenv()\n",
    "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n",
    "OPENAI_API_BASE_URL = os.getenv(\"OPENAI_API_BASE_URL\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 同步用法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "client = OpenAI(\n",
    "    api_key=OPENAI_API_KEY, \n",
    "    base_url=OPENAI_API_BASE_URL,\n",
    "    timeout=10 # 超时时间，单位为秒\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "非流式输出: \n",
      "在这个喧嚣的城市中，时间仿佛在不停地流逝，带走了许多美好的瞬间。清晨的阳光透过窗帘的缝隙，洒在床头，温暖而柔和。鸟儿在枝头欢快地歌唱，似乎在诉说着新一天的希望。这样的时刻，总是让我感受到生活的美好。\n",
      "\n",
      "走出家门，街道两旁的梧桐树在微风中轻轻摇曳，树叶沙沙作响，像是在低声吟唱。人们匆匆而过，脸上挂着忙碌的神情，仿佛每个人都在追逐着什么。可我却喜欢在这繁忙中，寻找那一丝宁静。偶尔停下脚步，望向天空，云朵在蓝天中悠然飘荡，仿佛在告诉我，生活不必如此急促。\n",
      "\n",
      "午后的阳光透过树影洒在地面，形成斑驳的光影。我喜欢在这样的时刻，找一个安静的角落，捧一本书，沉浸在文字的海洋中。书中的世界总是那么广阔，带我去往未知的地方，体验不同的人生。\n",
      "\n",
      "夜幕降临，城市的灯光逐渐亮起，像繁星点缀在黑夜的幕布上。此时的我，常常会在阳台上静静地望着远方，思考着生活的意义。或许，生活就是在这平凡的日子中，寻找那些闪光的瞬间，让心灵在忙碌中得到片刻的宁静与满足。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 非流式输出\n",
    "response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-mini\",\n",
    "    messages=[{\"role\": \"user\", \"content\": \"你好！请给我写一个300字的散文。\"}],\n",
    "    temperature=0.1,\n",
    "    stream=False, # 非流式输出\n",
    ")\n",
    "\n",
    "print(f\"非流式输出: \\n{response.choices[0].message.content}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "流式输出: \n",
      "在晨曦微露的时分，清新的空气仿佛带着露珠的芬芳，滋润着每一个角落。阳光透过树梢洒落在大地上，像是温暖的手轻轻抚摸，唤醒了沉睡了一夜的万物。小鸟在枝头欢快地鸣唱，似乎在诉说着新的希望与梦想，而晨露悄然滑落，打破了宁静的氛围，点滴在绿叶上，如同一颗颗晶莹的珍珠。\n",
      "\n",
      "漫步在这宁静的早晨，心中充满了无尽的美好与期待。路旁的花朵在微风中摇曳，展示着它们的娇艳，仿佛在向路人打招呼。每一片叶子，每一朵花，都是大自然精心雕琢的作品，它们在阳光下散发出生命的光辉，述说着生长与希望的故事。\n",
      "\n",
      "在这样的清晨，思绪也随之飞扬。生活的琐碎与烦恼仿佛在这一刻消失殆尽，取而代之的是对未来的畅想。无论前方的路途多么曲折，心中那份对美好生活的渴望始终是我前行的动力。人世间的繁华与喧嚣，纵使令人迷醉，但在这一刻，我更喜欢这份简单与宁静。\n",
      "\n",
      "时光悄然流逝，留给我们的是无数的瞬间与感动。每一个清晨都是新的开始，带着希望与勇气，踏上未知的旅程，迎接生命的每一次绽放。愿我们在这条路上，心怀梦想，勇敢追逐。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 流式输出\n",
    "response = client.chat.completions.create(\n",
    "    model=\"gpt-4o-mini\",\n",
    "    messages=[{\"role\": \"user\", \"content\": \"你好！请给我写一个300字的散文。\"}],\n",
    "    stream=True # 流式输出\n",
    ")\n",
    "\n",
    "print(\"流式输出: \")\n",
    "for chunk in response:\n",
    "    content = chunk.choices[0].delta.content\n",
    "    if content:\n",
    "        print(content, end=\"\", flush=True)\n",
    "print(\"\\n\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 异步用法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "client = AsyncOpenAI(\n",
    "    api_key=OPENAI_API_KEY, \n",
    "    base_url=OPENAI_API_BASE_URL,\n",
    "    timeout=10 # 超时时间，单位为秒\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "非流式输出: \n",
      "在这个瞬息万变的世界里，时间仿佛在呼吸，时而轻柔，时而激烈。清晨，阳光透过窗帘的缝隙，洒落在温暖的房间里，唤醒沉睡的静谧。鸟儿在枝头欢快地歌唱，清脆的声音如同一曲悦耳的乐章，响彻在耳畔，驱散了夜的倦意。\n",
      "\n",
      "大街上，行人匆匆，脸上写满了生活的故事与期盼。小贩的吆喝声、孩子的笑声交织在一起，构成了一幅生动的画卷。那些微小而美好的瞬间，如晨露般晶莹剔透，时刻提醒着我们去珍惜眼前的一切。\n",
      "\n",
      "黄昏时分，夕阳渐沉，天边的云彩染上了橘红的色彩，仿佛在诉说着一天的结束。我们常常在这时停下匆忙的脚步，望着那片渐变的天空，思绪随之飘荡。生活中有太多的忙碌与纷扰，让我们时常忘记了初心。或许，这正是生活的意义——在每一个平凡的日子里，找到能够让心灵宁静的片刻。\n",
      "\n",
      "夜幕降临，繁星闪烁，如同无数颗梦的种子在夜空中闪耀。每一颗星星都承载着一个愿望，酝酿着希望。生活如星空一般，尽管有时会被乌云掩盖，但终会迎来明亮的时刻。让我们在这喧嚣的时代里，寻找到属于自己的那份宁静与美好。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 非流式输出\n",
    "response = await client.chat.completions.create(\n",
    "    model=\"gpt-4o-mini\",\n",
    "    messages=[{\"role\": \"user\", \"content\": \"你好！请给我写一个300字的散文。\"}],\n",
    "    stream=False # 非流式输出\n",
    ")\n",
    "\n",
    "print(f\"非流式输出: \\n{response.choices[0].message.content}\\n\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "流式输出: \n",
      "在这个匆忙的世界里，时间总是像潮水般涌来，带走了我们的慢生活。清晨的第一缕阳光透过窗帘，洒在床头，温暖而柔和。鸟儿在树枝上欢快地鸣唱，似乎是在为新一天的开始而庆祝。起床后，我习惯于泡一杯香浓的咖啡，细细品味那苦涩中带着丝丝甘甜的滋味。\n",
      "\n",
      "窗外的景色映入眼帘，繁忙的街道上熙熙攘攘的人流，像是一条奔腾不息的河流。每个人都在追寻自己的目标，有的人神情专注，有的人面带微笑。而在这个瞬息万变的城市中，是否还有人停下脚步，仰望那片湛蓝的天空？\n",
      "\n",
      "午后的阳光透过树叶的缝隙洒下斑驳的光影，我喜欢在这样的时刻，找到一处宁静的角落，静静地读一本书。书中的文字如涓涓细流，将我带入一个不同的世界，那里有梦与希望，有爱与勇气。每一个字句都仿佛在诉说着生命的真谛，让我思索、感悟。\n",
      "\n",
      "夜幕降临，城市的灯光逐渐亮起，仿佛繁星洒落在大地上。我走在街头，耳边传来悦耳的音乐，心中充满了宁静与满足。生活，就是在这一点一滴的细节中，发现美好、品味幸福。或许，这正是生活的意义—在忙碌中寻找到内心的宁静，在简单中体会到丰盈。\n",
      "\n"
     ]
    }
   ],
   "source": [
    "# 流式输出\n",
    "async def astream_response():\n",
    "    response = await client.chat.completions.create(\n",
    "        model=\"gpt-4o-mini\",\n",
    "        messages=[{\"role\": \"user\", \"content\": \"你好！请给我写一个300字的散文。\"}],\n",
    "        stream=True # 流式输出\n",
    "    )\n",
    "\n",
    "    print(\"流式输出: \")\n",
    "    async for chunk in response:\n",
    "        content = chunk.choices[0].delta.content\n",
    "        if content:\n",
    "            print(content, end=\"\", flush=True)\n",
    "    print(\"\\n\")\n",
    "\n",
    "# asyncio.run(astream_response()) # notebook中无法运行\n",
    "await astream_response()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 介绍 新的 API mode：responses"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Responses vs. Chat Completions API\n",
    "https://platform.openai.com/docs/guides/responses-vs-chat-completions\n",
    "\n",
    "OpenAI 新增了一种 API mode：Responses。是 Chat Completions 的升级版。增加了一些内置的工具。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "from openai import OpenAI\n",
    "from dotenv import load_dotenv\n",
    "\n",
    "# 初始化环境变量\n",
    "load_dotenv()\n",
    "OPENAI_API_KEY = os.getenv(\"OPENAI_API_KEY\")\n",
    "OPENAI_API_BASE_URL = os.getenv(\"OPENAI_API_BASE_URL\")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "从前有一只独角兽，每当夜空下雨时，它的角会发出柔和的光芒，照亮整个森林，让所有的小动物都安心入睡。\n"
     ]
    }
   ],
   "source": [
    "client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_API_BASE_URL)\n",
    "\n",
    "completion = client.chat.completions.create(\n",
    "  model=\"gpt-4o\",\n",
    "  messages=[\n",
    "      {\n",
    "          \"role\": \"user\",\n",
    "          \"content\": \"写一个关于独角兽的单句睡前故事。\"\n",
    "      }\n",
    "  ]\n",
    ")\n",
    "\n",
    "print(completion.choices[0].message.content)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'OpenAI' object has no attribute 'responses'",
     "output_type": "error",
     "traceback": [
      "\u001b[31m---------------------------------------------------------------------------\u001b[39m",
      "\u001b[31mAttributeError\u001b[39m                            Traceback (most recent call last)",
      "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[11]\u001b[39m\u001b[32m, line 4\u001b[39m\n\u001b[32m      1\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mopenai\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m OpenAI\n\u001b[32m      2\u001b[39m client = OpenAI()\n\u001b[32m----> \u001b[39m\u001b[32m4\u001b[39m response = \u001b[43mclient\u001b[49m\u001b[43m.\u001b[49m\u001b[43mresponses\u001b[49m.create(\n\u001b[32m      5\u001b[39m   model=\u001b[33m\"\u001b[39m\u001b[33mgpt-4o\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m      6\u001b[39m   \u001b[38;5;28minput\u001b[39m=[\n\u001b[32m      7\u001b[39m       {\n\u001b[32m      8\u001b[39m           \u001b[33m\"\u001b[39m\u001b[33mrole\u001b[39m\u001b[33m\"\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33muser\u001b[39m\u001b[33m\"\u001b[39m,\n\u001b[32m      9\u001b[39m           \u001b[33m\"\u001b[39m\u001b[33mcontent\u001b[39m\u001b[33m\"\u001b[39m: \u001b[33m\"\u001b[39m\u001b[33m写一个关于独角兽的单句睡前故事。\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m     10\u001b[39m       }\n\u001b[32m     11\u001b[39m   ]\n\u001b[32m     12\u001b[39m )\n\u001b[32m     14\u001b[39m \u001b[38;5;28mprint\u001b[39m(response.output_text)\n",
      "\u001b[31mAttributeError\u001b[39m: 'OpenAI' object has no attribute 'responses'"
     ]
    }
   ],
   "source": [
    "\n",
    "from openai import OpenAI\n",
    "client = OpenAI()\n",
    "\n",
    "response = client.responses.create(\n",
    "  model=\"gpt-4o\",\n",
    "  input=[\n",
    "      {\n",
    "          \"role\": \"user\",\n",
    "          \"content\": \"写一个关于独角兽的单句睡前故事。\"\n",
    "      }\n",
    "  ]\n",
    ")\n",
    "\n",
    "print(response.output_text)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "我当前的openai库（1.63.0）还不支持responses api。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 介绍 function call 的用法"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "FunctionCall(arguments='{\\n  \"location\": \"Paris, France\"\\n}', name='get_weather')\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\ngpt-4o: FunctionCall(arguments=\\'{\"location\":\"Paris, France\"}\\', name=\\'get_weather\\')\\ngpt-4: FunctionCall(arguments=\\'{\"location\":\"Paris, France\"}\\', name=\\'get_weather\\')\\n'"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openai import OpenAI\n",
    "\n",
    "client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_API_BASE_URL)\n",
    "\n",
    "functions = [{\n",
    "    \"type\": \"function\",\n",
    "    \"name\": \"get_weather\",\n",
    "    \"description\": \"Get current temperature for a given location.\",\n",
    "    \"parameters\": {\n",
    "        \"type\": \"object\",\n",
    "        \"properties\": {\n",
    "            \"location\": {\n",
    "                \"type\": \"string\",\n",
    "                \"description\": \"City and country e.g. Bogotá, Colombia\"\n",
    "            }\n",
    "        },\n",
    "        \"required\": [\n",
    "            \"location\"\n",
    "        ],\n",
    "        \"additionalProperties\": False\n",
    "    },\n",
    "}]\n",
    "\n",
    "# gpt-4o 时 不支持 strict 参数\n",
    "# gpt-4 时 支持 strict 参数\n",
    "\n",
    "completion = client.chat.completions.create(\n",
    "    model=\"gpt-4\",\n",
    "    messages=[{\"role\": \"user\", \"content\": \"What is the weather like in Paris today?\"}],\n",
    "    functions=functions,\n",
    "    function_call=\"auto\"\n",
    ")\n",
    "\n",
    "print(completion.choices[0].message.function_call)\n",
    "\n",
    "'''\n",
    "gpt-4o: FunctionCall(arguments='{\"location\":\"Paris, France\"}', name='get_weather')\n",
    "gpt-4: FunctionCall(arguments='{\\n  \"location\": \"Paris, France\"\\n}', name='get_weather')\n",
    "'''"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ChatCompletionMessageToolCall(id='call_Ee91iQP8goW0wEoHkQoklliI', function=Function(arguments='{\"location\":\"Paris, France\"}', name='get_weather'), type='function')]\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "'\\n[ChatCompletionMessageToolCall(id=\\'call_Tw0FbAxsPDPSUOzSe75dhpPM\\', function=Function(arguments=\\'{\\n  \"location\": \"Paris, France\"\\n}\\', name=\\'get_weather\\'), type=\\'function\\')]\\n'"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from openai import OpenAI\n",
    "\n",
    "client = OpenAI(api_key=OPENAI_API_KEY, base_url=OPENAI_API_BASE_URL)\n",
    "\n",
    "tools = [{\n",
    "    \"type\": \"function\",\n",
    "    \"function\": {\n",
    "        \"name\": \"get_weather\",\n",
    "        \"description\": \"Get current temperature for a given location.\",\n",
    "        \"parameters\": {\n",
    "            \"type\": \"object\",\n",
    "            \"properties\": {\n",
    "                \"location\": {\n",
    "                    \"type\": \"string\",\n",
    "                    \"description\": \"City and country e.g. Bogotá, Colombia\"\n",
    "                }\n",
    "            },\n",
    "            \"required\": [\n",
    "                \"location\"\n",
    "            ],\n",
    "            \"additionalProperties\": False\n",
    "        },\n",
    "        \"strict\": True\n",
    "    }\n",
    "}]\n",
    "\n",
    "completion = client.chat.completions.create(\n",
    "    model=\"gpt-4o\",\n",
    "    messages=[{\"role\": \"user\", \"content\": \"What is the weather like in Paris today?\"}],\n",
    "    tools=tools\n",
    ")\n",
    "\n",
    "print(completion.choices[0].message.tool_calls)\n",
    "\n",
    "\"\"\"\n",
    "gpt-4o: [ChatCompletionMessageToolCall(id='call_Ee91iQP8goW0wEoHkQoklliI', function=Function(arguments='{\"location\":\"Paris, France\"}', name='get_weather'), type='function')]\n",
    "gpt-4: [ChatCompletionMessageToolCall(id='call_Tw0FbAxsPDPSUOzSe75dhpPM', function=Function(arguments='{\\n  \"location\": \"Paris, France\"\\n}', name='get_weather'), type='function')]\n",
    "\"\"\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "chatbot",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.11"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
